package com.gengzp.common.document.core;

import com.gengzp.common.document.annotations.Api;
import com.gengzp.common.document.annotations.ApiModelProperty;
import com.gengzp.common.document.model.dto.FieldDocumentDto;
import com.gengzp.common.document.model.resp.ControllerDocumentResp;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @ClassName DocumentCoreFunc
 * @Description 接口文档核心方法
 * @Author gengzp
 * @Date 2025/5/25 1:15
 */
@Component
public class DocumentCoreFunc {

    /**
     * 根据 bean 对象组装控制器接口文档
     *
     * @param bean bean 对象
     * @return 控制器接口文档
     */
    public static ControllerDocumentResp buildControllerDocumentByBean(Object bean) {
        ControllerDocumentResp model = new ControllerDocumentResp();

        // 获取class文件
        Class<?> clazz = bean.getClass();
        // 获取 @Api 注解中的值
        String tag = clazz.getAnnotation(Api.class).tags();
        // 获取 @RequestMapping 注解中的值
        String url = clazz.getAnnotation(RequestMapping.class).value()[0];

        model.setControllerDescription(tag);
        model.setControllerUrl(url);
        return model;
    }

    /**
     * 从 bean 中获取字段的接口文档
     *
     * @param bean bean对象
     * @return 字段的接口文档
     */
    public static List<FieldDocumentDto> getFieldDocumentFromBean(Class<?> bean, Set<Class<?>> genericClasses) {
        List<FieldDocumentDto> result = new ArrayList<>();

        // 循环组装字段文档信息
        for (Field field : bean.getDeclaredFields()) {
            // 若字段没有 @ApiModelProperty 注解, 则不在文档展示该字段, 跳过
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty == null) {
                continue;
            }

            FieldDocumentDto fieldDocumentDto = new FieldDocumentDto();
            fieldDocumentDto.setFieldName(field.getName());
            fieldDocumentDto.setFieldType(captureFileName(field.getType().getName()));
            fieldDocumentDto.setFieldDescription(apiModelProperty.value());
            fieldDocumentDto.setRequired(apiModelProperty.required());
            result.add(fieldDocumentDto);

            // 如果当前字段类型不是jdk提供的数据类型, 则该类型需要额外输出接口文档
            if (!checkFieldIsJdkDataType(field)) {
                genericClasses.add(field.getType());
            }

            // 如果字段是集合, 则取出泛型作为描述
            if (apiModelProperty.collectionGenericClass() != void.class) {
                fieldDocumentDto.setGenericInfoDescription("集合泛型: " + apiModelProperty.collectionGenericClass().getName());
            }

            // 如果字段是枚举, 则取出枚举的描述作为接口文档
            if (apiModelProperty.enumClass() != void.class) {
                fieldDocumentDto.setGenericInfoDescription("枚举描述: " + convertEnumClass2Description(apiModelProperty.enumClass()));
            }

        }

        return result;
    }

    /**
     * 截取文件名称
     *
     * @param completeFileName 完整的文件名
     * @return 截取后的文件名的部分
     */
    public static String captureFileName(String completeFileName) {
        if (completeFileName == null || completeFileName.isBlank()) {
            return "";
        }
        String[] split = completeFileName.split("\\.");
        return split[split.length - 1];
    }

    /**
     * 校验字段是否是jdk提供的数据类型
     *
     * @param field 字段
     * @return true/false
     */
    public static Boolean checkFieldIsJdkDataType(Field field) {
        return Arrays.asList("short", "int", "long", "float", "double",
                        "char", "boolean", "byte", "string", "list", "set", "map", "object", "integer", "date", "datetime")
                .contains(captureFileName(field.getType().getName()).toLowerCase());
    }

    /**
     * 校验字段的类型名称是否是jdk提供的基础数据类型
     *
     * @param fieldTypeName 字段类名
     * @return true/false
     */
    public static Boolean checkFieldTypeNameIsJdkDataType(String fieldTypeName) {
        return Arrays.asList("short", "int", "long", "float", "double",
                        "char", "boolean", "byte", "string", "list", "set", "map", "object", "integer", "date", "datetime")
                .contains(fieldTypeName.toLowerCase());
    }

    /**
     * 转换枚举类为描述
     *
     * @param enumClass 枚举类
     * @return 描述
     */
    public static String convertEnumClass2Description(Class<?> enumClass) {
        if (!enumClass.isEnum()) {
            throw new IllegalArgumentException("输入的类不是枚举类型: " + enumClass.getName());
        }

        // 获取所有枚举常量
        Object[] constants = enumClass.getEnumConstants();
        if (constants == null || constants.length == 0) {
            return "";
        }

        StringBuilder sb = new StringBuilder();

        try {
            // 获取 getCode 和 getValue 方法
            Method getCode = enumClass.getMethod("getCode");
            Method getValue = enumClass.getMethod("getValue");

            for (Object constant : constants) {
                Integer code = (Integer) getCode.invoke(constant);
                String value = (String) getValue.invoke(constant);
                sb.append(code).append(": ").append(value).append("; ");
            }

            // 删除末尾多余的 "; "
            if (!sb.isEmpty()) {
                sb.delete(sb.length() - 2, sb.length());
            }

        } catch (Exception e) {
            throw new RuntimeException("枚举类转换失败: " + enumClass.getName(), e);
        }

        return sb.toString();
    }

}
